package com.example.udptestdemo.runnables;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

import org.json.JSONException;
import org.json.JSONObject;

import com.example.udptestdemo.SyncLock;
import com.example.udptestdemo.listeners.FinishListener;
import com.example.udptestdemo.listeners.MonitorRefreshListener;
import com.example.udptestdemo.servers.BaseSocket;
import com.example.udptestdemo.utils.Convert;
import com.example.udptestdemo.utils.DataFormat;
import com.example.udptestdemo.utils.FileUtil;

public class MonitorRunnable implements Runnable {

	private final static byte CMD_DATA = 0x0A, CMD_DATA_END = 0x10, CMD_DATA_BEGIN = 0x11, CMD_FATAL = 0x1F;

	private final static byte ERR_NO_SU = 0x10, ERR_RUNTIME = 0x11;

	private MonitorRefreshListener mMonitorRefreshListener;
	private FinishListener mFinishListener;

	private BaseSocket mSocket;
	private InetAddress mRemoteAddress;
	private int mRemotePort;

	private boolean mIsActive = true;

	private boolean mIsScreenError = false;
	private String mErrorContent = "";

	private RandomAccessFile mFileAccess;

	private FileChannel mFileChannel;

	private MappedByteBuffer mByteBuffer;

	private SyncLock mLock = new SyncLock();
	
	public boolean getRunStatus(){
		return mIsActive;
	}

	public MonitorRunnable(BaseSocket socket, InetAddress address, int port) {
		this.mSocket = socket;
		this.mRemoteAddress = address;
		this.mRemotePort = port;
	}

	public void setListener(MonitorRefreshListener refresh_listener, FinishListener finish_listener) {
		this.mMonitorRefreshListener = refresh_listener;
		this.mFinishListener = finish_listener;
	}

	@Override
	public void run() {

		while (mIsActive && !mIsScreenError) {

			// 获取照片
			try {
				getScreenShot();
			} catch (JSONException e) {
				e.printStackTrace();
			}

			if (mLock.Wait(1000 * 20)) {
				mErrorContent = "接收超时, 退出接收";
				break;
			}
			// 判断如果屏幕端不能启动 则退出循环并弹出提示
			if (mIsScreenError)
				break;

			// 触发刷新UI控件
			if (mMonitorRefreshListener != null) {
				mMonitorRefreshListener.monitor_refresh();
			}

		}
		if (mIsActive) {
			mIsScreenError = true;
			mErrorContent = "用户主动退出了监控线程";
		}
		if (mFinishListener != null)
			mFinishListener.finish(!mIsScreenError, mErrorContent);

		if (mFileChannel != null) {
			try {
				mFileChannel.close();
				mFileAccess.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	private void getScreenShot() throws JSONException {
		JSONObject json_obj = new JSONObject();
		json_obj.put("cmd", 3);

		byte[] send_buffer = DataFormat.formatCommand(json_obj.toString());
		DatagramPacket packet = new DatagramPacket(send_buffer, send_buffer.length, mRemoteAddress, mRemotePort);
		try {
			mSocket.sendDatagramPacket(packet);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void dealWithData(byte[] data, int real_len) {
		int type = data[2];
		if (type == CMD_DATA) {

			// 写文件
			byte[] index_bytes = new byte[4];
			System.arraycopy(data, 3, index_bytes, 0, index_bytes.length);
			int index = Convert.bytes2UnsignedInt(index_bytes);
			mByteBuffer.position(index);
			mByteBuffer.put(data, 10, real_len - 10);

		} else if (type == CMD_DATA_BEGIN) {
			byte[] file_size_bytes = new byte[4];
			System.arraycopy(data, 3, file_size_bytes, 0, file_size_bytes.length);

			int file_size = Convert.bytes2UnsignedInt(file_size_bytes);
			if (mFileAccess == null) {
				String file_path = FileUtil.MonitorFileTemp;

				try {
					mFileAccess = new RandomAccessFile(file_path, "rw");
					mFileChannel = mFileAccess.getChannel();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			try {
				mFileChannel.truncate(0);
				mByteBuffer = mFileChannel.map(FileChannel.MapMode.READ_WRITE, 0, file_size);
				System.out.println("monitor recv pic is begin");
			} catch (IOException e) {
				mIsActive = false;
				e.printStackTrace();
			} // 清空文件

		} else if (type == CMD_DATA_END) {
			try {
				// 写入磁盘
				mFileChannel.force(true);
				mLock.Notify();
				System.out.println("monitor recv pic is end");
			} catch (IOException e) {
				e.printStackTrace();
			}

		} else if (type == CMD_FATAL) {
			System.out.println(" send  error !");
			if (data[3] == ERR_NO_SU) {
				mIsScreenError = true;
				System.out.println("screen  no  su");
				mErrorContent = "Screen no su !";
			} else if (data[3] == ERR_RUNTIME) {
				mIsScreenError = true;
				System.out.println("screen run error!");
				mErrorContent = "Screen run error!";
			}

		}
	}

	public void onDestory() {
		mLock.Notify();
		mIsActive = false;
	}

}
